﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace NumSkull
{
    public static class StatisticsExtensions
    {
        public static double Mean(this IEnumerable<double> data)
        {
            if (data.IsNullOrEmpty()) return default(double);

            var mean = (1d / data.Count()) * data.Sum();
            return mean;
        }

        public static double Median(this IEnumerable<double> data)
        {
            if (data.IsNullOrEmpty()) return default(double);

            var sorted = data.OrderBy(d => d);
            var count = sorted.Count();

            var isEven = count % 2 == 0;
            var middle = sorted.Skip((count - 1) / 2).Take(isEven ? 2 : 1);

            var median = middle.Average();
            return median;
        }

        public static IEnumerable<double> Mode(this IEnumerable<double> data)
        {
            if (data.IsNullOrEmpty()) return Enumerable.Empty<double>();

            var mode = data.GroupBy(d => d).Select(g => new
                                                            {
                                                                Value = g.Key,
                                                                Count = g.Count()
                                                            });

            var max = mode.Max(d => d.Count);
            var groupedModes = mode.OrderByDescending(d => d.Value);
            var filtered = groupedModes.Where(d => d.Count == max && max > 1);

            var modes = filtered.Select(g => g.Value);
            return modes.ToList();
        }

        public static double Variance(this IEnumerable<double> data)
        {
            if (data.IsNullOrEmpty()) return default(double);

            var mean = data.Mean();
            var values = data.Select(v => Math.Pow(v - mean, 2));
            var variance = Math.Pow((1d / (data.Count() - 1) * (values.Sum())), 2);
            return variance;
        }

        public static double StandardDeviation(this IEnumerable<double> data)
        {
            var variance = data.Variance();
            var standardDeviation = Math.Sqrt(variance);
            return standardDeviation;
        }
    }
}
